package com.zqh.myfmmall.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zqh.myfmmall.constants.RedisExpireTime;
import com.zqh.myfmmall.dao.CategoryDao;
import com.zqh.myfmmall.entity.Category;
import com.zqh.myfmmall.redis.RedisUtil;
import com.zqh.myfmmall.result.Result;
import com.zqh.myfmmall.service.CategoryService;
import com.zqh.myfmmall.service.ProductService;
import com.zqh.myfmmall.vo.CategoryVo;
import com.zqh.myfmmall.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 商品分类 (Category)表服务实现类
 *
 * @author KONO 曾淇杭哒！
 * @since 2022-01-20 20:52:59
 */
@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, Category> implements CategoryService {
    @Resource
    private CategoryDao categoryDao;
    @Resource
    private ProductService productService;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public Result selectAllCategoriesByParentId(String parentId) {
        List<CategoryVo> categoryVos = categoryDao.selectAllCategories(parentId);
        return Result.success(categoryVos);
    }

    @Override
    public Result selectFirstLevelCategory() {
        List<CategoryVo> firstLevelCategories = (List<CategoryVo>) selectAllCategoriesByParentId("0").getData();
        //查询每个一级菜单中销量最高的六个产品用于首页展示推荐
        for (CategoryVo firstLevelCategory : firstLevelCategories) {
            List<ProductVo> highestSaleProducts = productService.firstLevelCategoriesHighestSaleProduct(firstLevelCategory.getCategoryId());
            firstLevelCategory.setRecommendedProducts(highestSaleProducts);
        }
        return Result.success(firstLevelCategories);
    }

    @Override
    public Result selectAllCategories() throws JsonProcessingException {
        Result result = null;
        List<CategoryVo> categorievos = (List<CategoryVo>) redisUtil.get("categories-list");
        //categories-list一级缓存不为空
        if (categorievos != null) {
                result = Result.success(categorievos);
        }
        else {
            //二级缓存配合redis分布式锁解决缓存击穿问题
            List<CategoryVo> categorievosBackup = (List<CategoryVo>)redisUtil.get("categories-list-backup");
            if (categorievosBackup != null) {
                //使用缓存备份作为数据返回
                result = Result.success(categorievosBackup);
                //添加更新categories缓存的锁，从而只启动一个线程来更新缓存
                boolean isAbsent = redisUtil.setnx("categories-list-lock", "1");
                //加锁成功则进入进行缓存更新操作
                if (isAbsent) {
                    Object data = selectAllCategoriesByParentId("0").getData();
                        //更新缓存
                        redisUtil.set("categories-list", data,
                                RedisExpireTime.CATEGORY.getTime(),RedisExpireTime.CATEGORY.getTimeUnit());
                        redisUtil.set("categories-list-backup", data,
                                RedisExpireTime.CATEGORY.getTime() + 3,RedisExpireTime.CATEGORY.getTimeUnit());
                    //释放锁
                    redisUtil.del("categories-list-lock");
                }
                //初始categories-list和categories-list-backup缓存数据(即第一次访问时进行)，但是这里可以通过缓存预热来优化，暂时先这样写
            }else{
                result = selectAllCategoriesByParentId("0");
                Object data = result.getData();
                    //更新缓存
                redisUtil.set("categories-list", categorievos,
                        RedisExpireTime.CATEGORY.getTime(),RedisExpireTime.CATEGORY.getTimeUnit());
                redisUtil.set("categories-list-backup", categorievos,
                        RedisExpireTime.CATEGORY.getTime() + 3,RedisExpireTime.CATEGORY.getTimeUnit());
            }
        }
        return result;
    }
}

